查看原文
其他

.NET Core 微服务快速开发框架 Viper 限流

DotNet 2021-09-23

(给DotNet加星标,提升.Net技能

转自:杜燕明
cnblogs.com/duyanming/p/13846451.html

一、Viper是什么?


Viper是.NET平台下的Anno微服务框架的一个示例项目。入门简单、安全、稳定、高可用、全平台可监控。底层通讯可以随意切换thrift grpc。


自带服务发现、调用链追踪、Cron 调度、限流、事件总线、CQRS 、DDD、类似MVC的开发体验,插件化开发


一个不可监控的微服务平台是可怕的,出了问题 难以准确定位问题的根源, Anno则提供了一套完整的监控体系,包括链路追踪、服务占用的系统资源、系统自身 CPU、内存、硬盘使用率实时可监控等等。


本文要说的是.NET Core 微服务Viper的限流,防止恶意攻击,做一个打不死的小强。


如果对Viper不了解的可以看上篇文章


《.NET Core 微服务 快速开发框架 Viper 初体验》





github:https://github.com/duyanming/Viper


文档地址:https://duyanming.github.io/


体验地址:http://140.143.207.244/

(体验用户为anno 密码123456 同一时间一个用户只能在一个终端登录用户多的时候可能发生强制退出的情况,稍后登录体验)


二、限流Anno.RateLimit


限流用到两个库 Anno.RateLimit、IPAddressRange。Anno.RateLimit为限流组件,IPAddressRange为IP匹配组件。


IPAddressRange地址:https://github.com/jsakamoto/ipaddressrange


using NetTools;
...
// rangeA.Begin is "192.168.0.0", and rangeA.End is "192.168.0.255".

var rangeA = IPAddressRange.Parse("192.168.0.0/255.255.255.0");
rangeA.Contains(IPAddress.Parse("192.168.0.34")); // is True.
rangeA.Contains(IPAddress.Parse("192.168.10.1")); // is False.
rangeA.ToCidrString(); // is 192.168.0.0/24

// rangeB.Begin is "192.168.0.10", and rangeB.End is "192.168.10.20".
var rangeB1 = IPAddressRange.Parse("192.168.0.10 - 192.168.10.20");
rangeB1.Contains(IPAddress.Parse("192.168.3.45")); // is True.
rangeB1.Contains(IPAddress.Parse("192.168.0.9")); // is False.

// Support shortcut range description.
// ("192.168.10.10-20" means range of begin:192.168.10.10 to end:192.168.10.20.)
var rangeB2 = IPAddressRange.Parse("192.168.10.10-20");

// Support CIDR expression and IPv6.
var rangeC = IPAddressRange.Parse("fe80::/10");
rangeC.Contains(IPAddress.Parse("fe80::d503:4ee:3882:c586%3")); // is True.
rangeC.Contains(IPAddress.Parse("::1")); // is False.

// "Contains()" method also support IPAddressRange argument.
var rangeD1 = IPAddressRange.Parse("192.168.0.0/16");
var rangeD2 = IPAddressRange.Parse("192.168.10.0/24");
rangeD1.Contains(rangeD2); // is True.

// IEnumerable<IPAddress> support, it's lazy evaluation.
foreach (var ip in IPAddressRange.Parse("192.168.0.1/23"))
{
Console.WriteLine(ip);
}

// You can use LINQ via "AsEnumerable()" method.
var longValues = IPAddressRange.Parse("192.168.0.1/23")
.AsEnumerable()
.Select(ip => BitConvert.ToInt32(ip.GetAddressBytes(), 0))
.Select(adr => adr.ToString("X8"));
Console.WriteLine(string.Join(",", longValues);

// Constructors from IPAddress objects.
var ipBegin = IPAddress.Parse("192.168.0.1");
var ipEnd = IPAddress.Parse("192.168.0.128");
var ipSubnet = IPAddress.Parse("255.255.255.0");

var rangeE = new IPAddressRange(); // This means "0.0.0.0/0".
var rangeF = new IPAddressRange(ipBegin, ipEnd);
var rangeG = new IPAddressRange(ipBegin, maskLength: 24);
var rangeH = new IPAddressRange(ipBegin, IPAddressRange.SubnetMaskLength(ipSubnet));

// Calculates Cidr subnets
var rangeI = IPAddressRange.Parse("192.168.0.0-192.168.0.254");
rangeI.ToCidrString(); // is 192.168.0.0/24


Anno.RateLimit限流组件的使用


Anno.RateLimit支持令牌桶和漏桶两种算法


using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Anno.RateLimit;
namespace ConsoleTest
{
/// <summary>
/// 限流测试
/// </summary>
public class RateLimitTest
{
/// <summary>
/// 限流测试
/// </summary>
public void Handle()
{
var service = LimitingFactory.Build(TimeSpan.FromSeconds(1),LimitingType.TokenBucket, 20, 5);
Console.Write("请输入线程数:");
long.TryParse(Console.ReadLine(), out long th);
for (int i = 0; i < th; i++)
{
var t = Task.Factory.StartNew(() =>
{
while (true)
{
var result = service.Request();
//如果返回true,说明可以进行业务处理,否则需要继续等待
if (result)
{
Console.WriteLine($"{DateTime.Now}--{Task.CurrentId}---ok");
//业务处理......
}
else
Thread.Sleep(100);
}
}, TaskCreationOptions.LongRunning);
}
}
}
}


三、Viper限流


下图是用Jmeter测试线上http://140.143.207.244/ 的截图,下图红色部分为限流直接返回失败的记录,调用方为 NewApi目标服务为NewApi可以看到返回的信息为Trigger current limiting,


通过限流保证Viper成为一个打不死的小强



配置Viper的限流


{
"Target": {
"AppName": "ApiGateway",
"IpAddress": "127.0.0.1",
"Port": 7010,
"TraceOnOff": true
},
"Limit": {
"Enable": true,
"TagLimits": [
{
"channel": "*",
"router": "*",
"timeSpan": "1",//限流周期单位秒
"rps": 100,//周期内通过的请求个数
"limitSize": 100//令牌桶,漏桶池子大小
}
],
"IpLimit": {//ip限流
"timeSpan": 1,//限流周期单位秒
"rps": 100,//周期内通过的请求个数
"limitSize": 100//池子大小
},
"White": [//白名单 用法可以参考IPAddressRange
"0.0.0.1",
"192.168.1.2",
"192.168.2.18"
],
"Black": [//黑名单
"0.0.0.2",
"192.168.3.18"
]
}
}


  • Limit.Enable:是否启用限流


  • Limit.TagLimits:根据Tag限流


channel: Anno.Plugs.Logic//请求tag 必须参数
router: Platform      //模块名称(没有Module) 必须参数
method: GetFunc      //模块方法 必须参数
profile: fSFhFv5d4ZlC/JTz1EvoBDNWTr+sNtAhKWTuykqfZHU2oB8/W7aUayqsXmFJXPlR
uname: yrm


  • Limit.IpLimit:根据客户端Ip限流


  • Limit.White:白名单


  • Limit.IpLimit:黑名单


关于更多的Viper限流细节可参考github:https://github.com/duyanming/Viper/blob/master/Viper/Extensions/Middleware/DymWebHostBuilderExtensions.cs


以上分享了,Viper网关的限流。后面分享每个微服务如何通过注解方式限流、以及请求缓存、ViperService的 全局过滤器、模块过滤器、方法过滤器。


过滤器类型有,授权过滤器、异常过滤器、Action过滤器。Anno.EngineData.Filters


两种常用算法


令牌桶(Token Bucket)和漏桶(leaky bucket)是 最常用的两种限流的算法。


令牌桶主要是控制注入的速度,漏桶则是控制出的速度。


漏桶算法



令牌桶算法



关于更多限流只是可参考:


https://www.cnblogs.com/shanyou/p/4280546.html


https://www.cnblogs.com/vveiliang/p/9049393.html


Viper


github:https://github.com/duyanming/Viper


文档地址:https://duyanming.github.io/


体验地址:http://140.143.207.244/


(体验用户为anno 密码123456 同一时间一个用户只能在一个终端登录用户多的时候可能发生强制退出的情况,稍后登录体验)


关于Viper的更多内容,随后更新。敬请关注。开源不易,感谢Star。


- EOF -



推荐阅读  点击标题可跳转
用Span对C#进程中三大内存区域进行统一访问 ,太厉害了! 首个.NET 5+Vue.js业务模块化快速开发框架【NetModular】发布C# 8.0 之后接口已经不再单纯了,我懵逼了!


看完本文有收获?请转发分享给更多人

关注「DotNet」加星标,提升.Net技能 

好文章,我在看❤️

: . Video Mini Program Like ,轻点两下取消赞 Wow ,轻点两下取消在看

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存